package com.billionsfinance.crs;

import com.billionsfinance.crs.model.system.GenerateCodeModule;
import com.billionsfinance.crs.utils.FreemarkerTemplateHelper;
import com.billionsfinance.crs.utils.MyBatisQueryUtils;
import com.billionsfinance.crs.utils.SystemConfig;
import freemarker.template.TemplateException;
import org.aeonbits.owner.ConfigFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码自动生成工具类
 *
 * @ClassName: GenerateCodeMain
 * @author: WeiHui.Zhang
 * @date: 2016/9/13 16:13
 * @version: v1.0.0
 */
public class GenerateCodeMain {

	private static final Logger LOGGER = LoggerFactory.getLogger(GenerateCodeMain.class);

	private static SystemConfig config;

	public enum TemplateType {
		Dao("Dao.ftl"), //
		Service("Service.ftl"), //
		ServiceImpl("ServiceImpl.ftl"), //
		Server("Server.ftl"), //
		ServerImpl("ServerImpl.ftl"), //
		Mapper("Mapper.ftl"), //
		Module("Module.ftl"), //
		Controller("Controller.ftl"), //
		MyBatisInfo("MyBatisInfo.ftl");

		private final String code;

		TemplateType(String code) {
			this.code = code;
		}

		public String getCode() {
			return this.code;
		}
	}

	/**
	 * 业务类型
	 */
	public enum ModuleType {
		system
	}

	/**
	 * 生成代码
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		long begin = System.currentTimeMillis();
		LOGGER.info("---------------生成代码开始--------------");
		config = ConfigFactory.create(SystemConfig.class);
		mkdirs(config);
		List<GenerateCodeModule> tableInfo = getTableInfo("CRS_INTERFACE_CALL_LOG");
		generateAll(tableInfo, "CRS_INTERFACE_CALL_LOG", ModuleType.system.name(), "InterfaceCallLog",
				"历史人员状态");
		long end = System.currentTimeMillis();
		LOGGER.info("---------------生成代码结束，耗时:{}ms!--------------", (end - begin));
		autoOpenDir();
	}

	public static void autoOpenDir() {
		try {
			String osName = System.getProperty("os.name");
			if (osName != null) {
				if (osName.contains("Mac")) {
					Runtime.getRuntime().exec("open " + config.moduleOutPath());
				} else if (osName.contains("Windows")) {
					Runtime.getRuntime().exec("cmd /c start " + config.moduleOutPath());
				} else {
					System.err.println("save dir:" + config.moduleOutPath());
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void mkdirs(SystemConfig systemConfig) {
		File defaultOutPath = new File(systemConfig.defaultOutPath());
		defaultOutPath.mkdirs();

		File moduleOutPath = new File(systemConfig.moduleOutPath());
		moduleOutPath.mkdirs();

		File daoOutPath = new File(systemConfig.daoOutPath());
		daoOutPath.mkdirs();

		File serviceOutPath = new File(systemConfig.serviceOutPath());
		serviceOutPath.mkdirs();

		File serverOutPath = new File(systemConfig.serverOutPath());
		serverOutPath.mkdirs();

		File mapperOutPath = new File(systemConfig.mapperOutPath());
		mapperOutPath.mkdirs();

		File controllerOutPath = new File(systemConfig.controllerOutPath());
		controllerOutPath.mkdirs();

		File serverImplOutPath = new File(systemConfig.serverImplOutPath());
		serverImplOutPath.mkdirs();

		File serviceImplOutPath = new File(systemConfig.serviceImplOutPath());
		serviceImplOutPath.mkdirs();
	}

	/**
	 * 生成所有的文件
	 *
	 * @param list       表结构数据
	 * @param tableName  表名
	 * @param moduleType 生成的表属于哪个大类，如system,business,workflow
	 * @param module     生成的实体名称
	 */

	private static void generateAll(List<GenerateCodeModule> list, String tableName, String moduleType, String module,
	                                String tableDesc) {
		generateCode(list, tableName, TemplateType.Module, moduleType, module, config.defaultOutPath(), tableDesc);
		generateCode(list, tableName, TemplateType.Mapper, moduleType, module, config.mapperOutPath(), tableDesc);
		generateCode(list, tableName, TemplateType.Dao, moduleType, module, config.daoOutPath(), tableDesc);
		generateCode(list, tableName, TemplateType.Service, moduleType, module, config.serviceOutPath(), tableDesc);
		generateCode(list, tableName, TemplateType.ServiceImpl, moduleType, module, config.serviceImplOutPath(),
				tableDesc);
		generateCode(list, tableName, TemplateType.Server, moduleType, module, config.serverOutPath(), tableDesc);
		generateCode(list, tableName, TemplateType.ServerImpl, moduleType, module, config.serverImplOutPath(),
				tableDesc);
		generateCode(list, tableName, TemplateType.Controller, moduleType, module, config.controllerOutPath(),
				tableDesc);
		generateMyBatisInfo(TemplateType.MyBatisInfo, moduleType, module, config.defaultOutPath(), tableDesc);
	}

	/**
	 * 生成代码文件
	 *
	 * @param list         要生成的表对应的表结构数据 通过getTableInfo()方法拿到
	 * @param tableName    要生成的表名
	 * @param templateType 模版枚举，详情参考类上面的TemplateType枚举
	 * @param moduleType   要生成的module属于哪一类,比如system ,workflow,business
	 * @param module       表名对应的实体名称 比如crs_process_module 对应的就是ProcessModule
	 * @param fileOutPath  文件输出目录
	 */
	private static void generateCode(List<GenerateCodeModule> list, String tableName, TemplateType templateType,
	                                 String moduleType, String module, String fileOutPath, String tableDesc) {
		String path = SystemConfig.TEMPLATE_PATH;
		try {
			/**
			 * 输入模版需要参数
			 */
			Map<String, Object> root = new HashMap<>();
			root.put("moduleType", moduleType);
			root.put("createdName", config.createdName());
			root.put("createdTime", SystemConfig.createdTime);
			root.put("module", module);
			root.put("moduleInfoList", list);
			root.put("moduleTable", tableName);
			root.put("moduleSeq", module + "_SEQ");
			root.put("lowModule", module.substring(0, 1).toLowerCase() + module.substring(1));
			root.put("hessianDesc", tableDesc);
			/**
			 * 生成的文件名为 上面输入的Module + .java 如 ProcessModule.java
			 */
			StringBuffer sb = new StringBuffer(fileOutPath + "\\" + moduleType + "\\");
			sb.append(templateType.name().equals(TemplateType.Dao.name())
					|| templateType.name().equals(TemplateType.Server.name())
					|| templateType.name().equals(TemplateType.Service.name()) ? "I" + module + templateType.name()
					: templateType.name().equals(TemplateType.Module.name()) ? module
					: module + templateType.name());
			sb.append(templateType.name().equals(TemplateType.Mapper.name()) ? ".xml"
					: templateType.name().equals(TemplateType.MyBatisInfo.name()) ? ".txt" : ".java");
			/**
			 * 调用Freemarker模版引擎 传入模版名称 和参数 输出指定文件
			 */
			FreemarkerTemplateHelper.loadTemplateByFile(new File(path), templateType.getCode(), "UTF-8", root,
					sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TemplateException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成hessian sql文件和mybatis配置代码
	 *
	 * @param templateType 模版枚举，详情参考类上面的TemplateType枚举
	 * @param moduleType   要生成的module属于哪一类,比如system ,workflow,business
	 * @param module       表名对应的实体名称 比如crs_process_module 对应的就是ProcessModule
	 * @param fileOutPath  文件输出目录
	 * @param hessianDesc  hessian说明
	 */
	private static void generateMyBatisInfo(TemplateType templateType, String moduleType, String module,
	                                        String fileOutPath, String hessianDesc) {
		String path = SystemConfig.TEMPLATE_PATH;
		try {
			/**
			 * 输入模版需要参数
			 */
			Map<String, Object> root = new HashMap<>();
			root.put("moduleType", moduleType);
			root.put("module", module);
			root.put("lowModule", module.substring(0, 1).toLowerCase() + module.substring(1));
			root.put("hessianDesc", hessianDesc);
			/**
			 * 生成的文件名为 上面输入的Module + .java 如 ProcessModule.java
			 */
			StringBuffer sb = new StringBuffer(fileOutPath);
			sb.append(module + templateType.name());
			sb.append(".txt");
			/**
			 * 调用Freemarker模版引擎 传入模版名称 和参数 输出指定文件
			 */
			FreemarkerTemplateHelper.loadTemplateByFile(new File(path), templateType.getCode(), "UTF-8", root,
					sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TemplateException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 得到表的结构数据
	 *
	 * @param tableName
	 * @return
	 */
	public static List<GenerateCodeModule> getTableInfo(String tableName) {
		tableName = tableName.toUpperCase();
		GenerateCodeModule module = new GenerateCodeModule();
		module.setTableName(tableName);
		String statement = "GenerateCodeModuleMapper.findList";// 映射sql的标识字符串
		List<GenerateCodeModule> moduleInfoList = MyBatisQueryUtils.getInstance().getSessionFactory().openSession().selectList(statement,
				tableName);
		for (GenerateCodeModule m : moduleInfoList) {
			m.setPropertyName(m.getColumnName());
			m.setCapFieldName(m.getPropertyName());
			m.setFieldType(m.getJdbcType());
		}
		return moduleInfoList;
	}
}